
/********************************************
*
********************************************/


#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */

#include "d_freeque.h"
#include "d_atomic.h"
#include "d_log.h"

#define DMS_FREQUE_MAGIC  0xd7fb8a2c
#define DMS_FREQUE_USED_S 0xAB00BC00
#define DMS_FREQUE_FREE_S 0x00DE0012

typedef struct tagNode {
    UINT32 uiStatus;
    UINT32 uiData;
}FQ_NODE;

typedef union tagUnode {
    FQ_NODE stNode;
    UINT64  uiAtomic;
}FQ_UNODE;

typedef struct tagHead {
    UINT32 uiVersion;
    UINT32 uiIndex;
}FQ_HEAD;

typedef union tagUhead {
    FQ_HEAD  stHead;
    UINT64   uiAtomic;
}FQ_UHEAD;

typedef struct tagFreQueCtl {
    UINT32   uiMagic;
    UINT32   uiQueLen;
    FQ_UHEAD stPosR;
    FQ_UHEAD stPosW;
    FQ_UNODE astUnode[1];
}FQ_CTL;


UINT32 DMS_FreeQueInit(char * keys)
{
    return DMS_OK;
}

UINT32 DMS_FreeQueFini()
{
    return DMS_OK;
}


#if 0
UINT32 DMS_FreQueCreate(FQUE_HANDLE * pFreQue,UINT32 uiLength)
{
    UINT32   uil;
    UINT32   uiSize;
    FQ_CTL   * pstFQCtl;
    FQ_UNODE * pstUnode;

    if( NULL == pFreQue )
    {
        return DMS_INVALID_PARAM;
    }

    uiSize = sizeof(FQ_CTL) + (uiLength - 1) * sizeof(FQ_UNODE);
    pstFQCtl = (FQ_CTL *)DMS_MemAlloc(uiSize);

    if(NULL == pstFQCtl)
    {
        return DMS_NOSYS_MEM;
    }

    DMS_MemSet(pstFQCtl,0,uiSize);

    pstFQCtl->stMagic  = DMS_FREQUE_MAGIC;
    pstFQCtl->uiQueLen = uiLength;

    pstUnode = pstFQCtl->astUnode;
    for( uil = 0 ; uil < uiLength ; uil++ )
    {
        pstUnode->stNode.uiStatus = DMS_FREQUE_FREE_S;
    }

    *pFreQue = (FQUE_HANDLE)pstFQCtl;

    return DMS_OK;
}

UINT32 DMS_FreQueRead(FQUE_HANDLE FreQue,VOID ** pMsg)
{
    FQ_CTL * pstFQCtl = (FQ_CTL *)FreQue;
    FQ_UHEAD stReadOld;
    FQ_UHEAD stReadNew;
    FQ_UNODE stOldNode;
    FQ_UNODE stNewNode;
    FQ_UNODE * pstNode;

    if(NULL == FreQue || NULL == pMsg)
    {
        return DMS_INVALID_PARAM;
    }

    if( DMS_FREQUE_MAGIC != pstFQCtl->stMagic )
    {
        return DMS_INVALID_PARAM;
    }

try:

    if(pstFQCtl->stPosR.stHead.uiVersion == pstFQCtl->stPosW.stHead.uiVersion)
    {
        return DMS_ERR_FREQUE_NO_MSG;
    }

    stReadOld.uiAtomic = pstFQCtl->stPosR.uiAtomic;

    mb();

    pstNode = &pstFQCtl->astUnode[stReadOld.stHead.uiIndex];
    stOldNode.uiAtomic = pstNode->uiAtomic;

    if( DMS_FREQUE_FREE_S == stOldNode.stNode.uiStatus )
    {
        goto try;
    }

    *pMsg = stOldNode.stNode.uiData;

    stReadNew.stHead.uiIndex   = (stReadOld.stHead.usIndex + 1) % pstFQCtl->uiQueLen;
    stReadNew.stHead.uiVersion =  stReadOld.stHead.uiVersion + 1;

    mb();

    if(DMS_Atomic64(&(pstFQCtl->stPosR.uiAtomic),
                     (UINT64)stReadNew.uiAtomic,
                     (UINT64)stReadOld.uiAtomic))
    {
        stNewNode.stNode.uiStatus = DMS_FREQUE_FREE_S;
        stNewNode.stNode.uiData   = 0;

        if(DMS_Atomic64(&(pstNode->uiAtomic),
                         (UINT64)stNewNode.uiAtomic,
                         (UINT64)stOldNode.uiAtomic))
        {
            return DMS_OK;
        }
        else
        {
            exit(11);
        }

        return DMS_OK;
    }

    goto try;
}

UINT32 DMS_FreQueWrite(FQUE_HANDLE FreQue,VOID * pMsg )
{
    FQ_CTL * pstFQCtl = (FQ_CTL *)FreQue;
    FQ_UHEAD stWriteOld;
    FQ_UHEAD stWriteNew;
    FQ_UNODE stOldNode;
    FQ_UNODE stNewNode;
    FQ_UNODE * pstNode;

    if(NULL == FreQue || NULL == pMsg)
    {
        return DMS_INVALID_PARAM;
    }

    if( DMS_FREQUE_MAGIC != pstFQCtl->stMagic )
    {
        return DMS_INVALID_PARAM;
    }

try:

    if((pstFQCtl->stPosR.stHead.uiVersion + pstFQCtl->uiQueLen) == pstFQCtl->stPosW.stHead.uiVersion)
    {
        return DMS_ERR_FREQUE_FULL;
    }

    stWriteOld.uiAtomic = pstFQCtl->stPosW.uiAtomic;

    mb();

    pstNode = &pstFQCtl->astUnode[stWriteOld.stNode.usIndex]);

    stWriteNew.stHead.uiIndex   = (stWriteOld.stHead.uiIndex   + 1) % pstFQCtl->uiQueLen;
    stWriteNew.stHead.uiVersion =  stWriteOld.stHead.uiVersion + 1;

    mb();

    if(DMS_Atomic32(&(pstFQCtl->stNodeW.uiAtomic),
                     (UINT32)stWriteNew.uiAtomic,
                     (UINT32)stWriteOld.uiAtomic))
    {
        while( DMS_FREQUE_USED_S == pstNode->stNode.uiStatus)
        {
            ;
        }

        stOldNode.uiAtomic = pstNode->uiAtomic;

        stNewNode.stNode.uiData   = (UINT32)pMsg;
        stNewNode.stNode.uiStatus = DMS_FREQUE_USED_S;

        if(DMS_Atomic64(&(pstNode->uiAtomic),
                         (UINT64)stNewNode.uiAtomic,
                         (UINT64)stOldNode.uiAtomic))
        {
            return DMS_OK;
        }
        else
        {
            exit(11);
        }

        return DMS_OK;
    }

    goto try;
}

UINT32 DMS_FreQueDelete(FQUE_HANDLE FreQue )
{
    FQ_CTL * pstFQCtl = (FQ_CTL *)FreQue;

    if(NULL == FreQue )
    {
        return DMS_INVALID_PARAM;
    }

    if( DMS_FREQUE_MAGIC != pstFQCtl->stMagic )
    {
        return DMS_INVALID_PARAM;
    }

    pstFQCtl->stMagic = 0;

    return DMS_MemFree(pstFQCtl);;
}

#endif

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

